"""Configuration management for VectorDB microservice."""

import os
import yaml
from typing import Dict, Any, Optional
from pydantic import BaseModel, Field
from pathlib import Path


class ServiceConfig(BaseModel):
    """Service configuration model."""
    name: str = "vectordb-microservice"
    version: str = "1.0.0"
    host: str = "0.0.0.0"
    port: int = 8000
    workers: int = 1
    reload: bool = False
    log_level: str = "INFO"


class DatabaseConfig(BaseModel):
    """Database configuration model."""
    uri: str = "./data/vectordb"
    config_path: str = "./data/vectordb_config.json"
    max_connections: int = 10
    min_connections: int = 2
    connection_timeout: int = 30
    idle_timeout: int = 1800
    backup_on_startup: bool = True


class EmbeddingProviderConfig(BaseModel):
    """Embedding provider configuration."""
    api_key_env: str = ""
    base_url: str
    models: list[str]


class EmbeddingConfig(BaseModel):
    """Embedding configuration model."""
    provider: str = "ollama"
    model: str = "qwen3-embedding:0.6b"
    vector_dimension: int = 1024
    batch_size: int = 10
    max_retries: int = 3
    timeout: int = 30
    providers: Dict[str, EmbeddingProviderConfig] = Field(default_factory=dict)


class SearchConfig(BaseModel):
    """Search configuration model."""
    default_limit: int = 10
    max_limit: int = 100
    default_threshold: float = 0.0
    metric: str = "cosine"


class TableSchemaConfig(BaseModel):
    """Table schema configuration."""
    schema: Dict[str, str]


class TablesConfig(BaseModel):
    """Tables configuration model."""
    default: TableSchemaConfig
    documents: Optional[TableSchemaConfig] = None


class LoggingConfig(BaseModel):
    """Logging configuration model."""
    level: str = "INFO"
    format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    file: str = "logs/vectordb.log"
    max_size: int = 10485760
    backup_count: int = 5
    console: bool = True


class MonitoringConfig(BaseModel):
    """Monitoring configuration model."""
    enabled: bool = True
    metrics_endpoint: str = "/metrics"
    health_check_endpoint: str = "/health"


class SecurityConfig(BaseModel):
    """Security configuration model."""
    api_key_required: bool = False
    cors_origins: list[str] = Field(default_factory=lambda: ["*"])
    rate_limiting: Dict[str, Any] = Field(default_factory=dict)


class Config(BaseModel):
    """Main configuration model."""
    service: ServiceConfig = Field(default_factory=ServiceConfig)
    database: DatabaseConfig = Field(default_factory=DatabaseConfig)
    embedding: EmbeddingConfig = Field(default_factory=EmbeddingConfig)
    search: SearchConfig = Field(default_factory=SearchConfig)
    tables: TablesConfig = Field(default_factory=dict)
    logging: LoggingConfig = Field(default_factory=LoggingConfig)
    monitoring: MonitoringConfig = Field(default_factory=MonitoringConfig)
    security: SecurityConfig = Field(default_factory=SecurityConfig)


class ConfigManager:
    """Configuration manager for VectorDB microservice."""

    def __init__(self, config_path: Optional[str] = None):
        self.config_path = config_path or self._find_config_file()
        self._config: Optional[Config] = None
        self._load_config()

    def _find_config_file(self) -> str:
        """Find configuration file in common locations."""
        possible_paths = [
            "config.yaml",
            "config.yml",
            "./config/config.yaml",
            "./config/config.yml",
            os.path.expanduser("~/.vectordb/config.yaml"),
            "/etc/vectordb/config.yaml"
        ]

        for path in possible_paths:
            if os.path.exists(path):
                return path

        # Default to current directory
        return "config.yaml"

    def _load_config(self):
        """Load configuration from file."""
        if not os.path.exists(self.config_path):
            # Create default config if not exists
            self._create_default_config()
            return

        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                config_data = yaml.safe_load(f)

            self._config = Config(**config_data)
        except Exception as e:
            print(f"Error loading config from {self.config_path}: {e}")
            print("Using default configuration")
            self._config = Config()

    def _create_default_config(self):
        """Create default configuration file."""
        self._config = Config()

        # Ensure directory exists
        config_dir = os.path.dirname(self.config_path)
        if config_dir:
            os.makedirs(config_dir, exist_ok=True)

        # Save default config
        self.save_config()
        print(f"Created default configuration at {self.config_path}")

    def save_config(self):
        """Save current configuration to file."""
        try:
            config_dict = self._config.dict()

            # Ensure directory exists
            config_dir = os.path.dirname(self.config_path)
            if config_dir:
                os.makedirs(config_dir, exist_ok=True)

            with open(self.config_path, 'w', encoding='utf-8') as f:
                yaml.dump(config_dict, f, default_flow_style=False, allow_unicode=True)

        except Exception as e:
            print(f"Error saving config: {e}")

    @property
    def config(self) -> Config:
        """Get current configuration."""
        if self._config is None:
            self._load_config()
        return self._config

    def get_embedding_provider_config(self, provider: str) -> Optional[EmbeddingProviderConfig]:
        """Get configuration for specific embedding provider."""
        return self.config.embedding.providers.get(provider)

    def update_config(self, updates: Dict[str, Any]):
        """Update configuration with new values."""
        config_dict = self._config.dict()
        self._deep_update(config_dict, updates)
        self._config = Config(**config_dict)
        self.save_config()

    def _deep_update(self, base_dict: Dict, update_dict: Dict):
        """Deep update dictionary."""
        for key, value in update_dict.items():
            if key in base_dict and isinstance(base_dict[key], dict) and isinstance(value, dict):
                self._deep_update(base_dict[key], value)
            else:
                base_dict[key] = value


# Global config manager instance
config_manager = ConfigManager()

# Convenience functions
def get_config() -> Config:
    """Get global configuration."""
    return config_manager.config

def get_database_config() -> DatabaseConfig:
    """Get database configuration."""
    return config_manager.config.database

def get_embedding_config() -> EmbeddingConfig:
    """Get embedding configuration."""
    return config_manager.config.embedding

def get_service_config() -> ServiceConfig:
    """Get service configuration."""
    return config_manager.config.service